home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Think Class Libraries / MacTCP class library / MacTCP class sources / CTCPClient.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-30  |  11.9 KB  |  524 lines  |  [TEXT/KAHL]

  1. /*
  2.  
  3.   CTCPClient.c
  4.   Superclass:    CCollaborator
  5.  
  6.      The TCP client implementation for CTCP
  7.  
  8.   Copyright © NCSA, University of Illinois;    June 3, 1992
  9.   Eric Johnson, John Newlin and Igor Livshits
  10.   
  11.   This code may be used, modified, and distributed free of charge and obligation.
  12.   
  13. */
  14.  
  15. #include    "CTCPClient.h"
  16.  
  17. /*=====================*/
  18. /*===---------------===*/
  19.  
  20. OSErr CTCPClient::ITCPClient(void)
  21. Begin
  22.     CTCP*    theStream= Null;                                    //    Local temporary storage
  23.     OSErr    error;                                                        //    A possible error during initialization
  24.  
  25.     CCollaborator::ICollaborator();
  26.     
  27.     theStream= new CTCP;                                        //    Create our TCP stream
  28.     error= theStream->ITCP();
  29.     
  30.     itsStream= theStream;                                        //    Remember our stream object
  31.     
  32.     return error;
  33. End
  34.  
  35. /*===---------------===*/
  36.  
  37. void CTCPClient::Dispose(void)
  38. Begin
  39.     ForgetObject(itsStream);
  40.     
  41.     inherited::Dispose();
  42. End
  43.  
  44. /*===---------------===*/
  45.  
  46. OSErr CTCPClient::Create(Size streamLength)
  47. Begin
  48.     itsStream->MakeStreamBuffer(streamLength);
  49.  
  50.     return itsStream->Create();
  51. End
  52.  
  53. /*===---------------===*/
  54.  
  55. OSErr CTCPClient::OpenConnection(void)
  56. Begin    
  57.     return itsStream->ActiveOpen();
  58. End
  59.  
  60. /*===---------------===*/
  61.  
  62. OSErr CTCPClient::WaitForConnection(void)
  63. Begin    
  64.     return itsStream->PassiveOpen();
  65. End
  66.  
  67. /*===---------------===*/
  68.  
  69. OSErr CTCPClient::SendData(Ptr data, Size length)
  70. Begin
  71.     OSErr    error;                                                        //    A possible error condition
  72.  
  73.     itsStream->PlaceData(data, length);            //    Put our data into an out buffer
  74.     
  75. retrySend:
  76.     error= itsStream->Send();                                //    Send it
  77.     
  78.     if ( (error == kCommandTimeout) && (numRetries > 0) )
  79.     {
  80.         numRetries--;
  81.         goto retrySend;
  82.     }
  83.     
  84.     numRetries= Null;
  85.     
  86.     return itsStream->GetLastError();
  87. End
  88.  
  89. /*===---------------===*/
  90.  
  91. OSErr CTCPClient::ReceiveData(Ptr* data, Size* length)
  92. Begin                                                                            //    Wimpy and slow -- ignores the NoCopy alternative
  93.     register Size    newLength;
  94.     OSErr                    error;                                        //    A possible error condition
  95.     
  96.     itsStream->CreateInputBuffer(data, *length);
  97.  
  98. retryReceive:
  99.     error= itsStream->Rcv();
  100.     
  101.     if ( (error == kCommandTimeout) && (numRetries > 0) )
  102.     {
  103.         numRetries--;
  104.         goto retryReceive;
  105.     }
  106.     
  107.     if (error == noErr)
  108.     {
  109.         newLength= itsStream->GetInputLength();    //    Get the new data length
  110.         if (newLength < *length)
  111.             (*data)[newLength]= 0;
  112.         
  113.         *length= newLength;
  114.     }
  115.         
  116.     numRetries= Null;
  117.     
  118.     return itsStream->GetLastError();
  119. End
  120.  
  121. /*===---------------===*/
  122.  
  123. OSErr CTCPClient::MyBufferReceiveData(Ptr data, Size* length)
  124. Begin
  125.     OSErr    error;
  126.     Ptr     theOldInputBuffer;
  127.     Size    theOldBufferLength;
  128.     
  129.     theOldInputBuffer= itsStream->GetInputBuffer();
  130.     theOldBufferLength= itsStream->GetInputLength();
  131.     
  132.     FailOSErr( itsStream->SetInputBuffer(data, *length) );
  133.  
  134.     TRY 
  135.     {
  136. retryReceive:
  137.         error= itsStream->Rcv();
  138.     
  139.         if ( (error == kCommandTimeout) && (numRetries > 0) )
  140.         {
  141.             --numRetries;
  142.             goto retryReceive;
  143.         }
  144.     
  145.         if (error == noErr)
  146.             *length = itsStream->GetInputLength();        //    How much did we get?
  147.         else
  148.             *length= Null;                                                        //    An error invalidated any received data
  149.     
  150.         numRetries= Null;
  151.     }
  152.     CATCH
  153.     {
  154.         if (theOldInputBuffer != Null)
  155.             FailOSErr( itsStream->SetInputBuffer(theOldInputBuffer, theOldBufferLength) );
  156.     }
  157.     ENDTRY;
  158.     
  159.                                                                                                 //    Restore original buffer
  160.                                                                                                 //  if it is not Null
  161.     if (theOldInputBuffer != Null)
  162.         FailOSErr( itsStream->SetInputBuffer(theOldInputBuffer, theOldBufferLength) );
  163.     
  164.     return itsStream->GetLastError();
  165. End
  166.  
  167. /*===--------------===*/
  168.  
  169. OSErr CTCPClient::Close(void)
  170. Begin
  171.     return itsStream->Close();
  172. End
  173.  
  174. /*===---------------===*/
  175.  
  176. OSErr CTCPClient::Abort(void)
  177. Begin
  178.     return itsStream->Abort();
  179. End
  180.  
  181. /*===---------------===*/
  182.  
  183. OSErr CTCPClient::Quit(void)
  184. Begin
  185.     return itsStream->Release();
  186. End
  187.  
  188. /*===---------------===*/
  189.  
  190. OSErr CTCPClient::Kill(void)
  191. Begin
  192.     TCPiopb                pb;                                                    //    Our parameters
  193.     ParmBlkPtr        parameters= &pb;                        //    Our parameters
  194.     
  195.     itsStream->GetParameters(¶meters);
  196.  
  197.     return PBKillIO(parameters, False);
  198. End
  199.  
  200. /*===---------------===*/
  201.  
  202. CTCP* CTCPClient::GetStream()
  203. Begin    
  204.     return itsStream;
  205. End
  206.  
  207. /*===---------------===*/
  208.  
  209. void CTCPClient::SetRetries(long count)
  210. Begin
  211.     numRetries= count;
  212. End
  213.  
  214. /*===---------------===*/
  215.  
  216. void CTCPClient::SetAddress(char* name, ip_addr address, ip_port port)
  217. Begin
  218.     if (!name || !address)
  219.         FailOSErr( ResolveAddress(name, &address) );
  220.         
  221.     itsStream->SetDestination(name, address, port);
  222. End
  223.  
  224. /*===---------------===*/
  225.  
  226. OSErr CTCPClient::ResolveAddress(char* name, ip_addr* address)
  227. Begin
  228.     hostInfoRec        host;                                                        //    Information about our host machine
  229.     char                    done= Null;                                            //    Completion flag from DNR
  230.     OSErr                    error= noErr;                                        //    A possible error condition
  231.     CDNR*                    theResolver= Null;                            //    Our DNR
  232.     
  233.     theResolver= new CDNR;
  234.     theResolver->IDNR(Null);
  235.     
  236.     if (!name)
  237.     {
  238.         name= NewPtrClear(kNameLength);
  239.         
  240.         error= theResolver->AddressToName(*address, &host, Null, &done);
  241.     }
  242.     else
  243.     {
  244.         error= theResolver->StringToAddress(name, &host, Null, &done);
  245.         *address= host.address[0];
  246.     }
  247.         
  248.     ForgetObject(theResolver);
  249.     
  250.     if ((error == noErr) && (*(host.name)))
  251.     {
  252.         strncpy(name, host.name, kNameLength);
  253.         name[strlen(name)-1]= Null;                                    //    Eliminate the trailing 
  254.     }
  255.  
  256.     return error;
  257. End
  258.  
  259. /*===---------------===*/
  260.  
  261. OSErr    CTCPClient::GetLocalAddress(ip_addr* address)
  262. Begin
  263.     OSErr        error= noErr;                                                    //    An error, if any
  264.     
  265. retryMyIP:
  266.     *address= this->itsStream->GetMyIPAddress();
  267.     error=         this->itsStream->GetLastError();
  268.     
  269.     if (error != noErr)
  270.     {
  271.         if  ((numRetries > 0) && (error == kCommandTimeout))
  272.         {
  273.             this->numRetries--;
  274.             goto retryMyIP;
  275.         }
  276.         else
  277.             *address= Null;
  278.     }
  279.     
  280.     this->numRetries= Null;
  281.     return error;
  282. End
  283.  
  284. /*===---------------===*/
  285.  
  286. OSErr    CTCPClient::GetLocalDotAddress(char* dotAddress)
  287. Begin
  288.     OSErr        error= noErr;                                                    //    An error, if any
  289.     ip_addr    address;                                                            //    Our address as a number
  290.     
  291.     error= this->GetLocalAddress(&address);
  292.     
  293.     if (error == noErr)
  294.     {
  295.         sprintf(dotAddress, "%lu.%lu.%lu.%lu",
  296.                         (address>>24), 
  297.                         (address>>16)&0x000000ff,
  298.                         (address>> 8)&0x000000ff,
  299.                         (address    )&0x000000ff);
  300.     }
  301.     
  302.     return error;
  303. End
  304.  
  305.  
  306.  
  307. /*===---------------===*/
  308.  
  309.  
  310. /*********************************
  311.  * ReadData
  312.  *  This functions checks to see if there is data available from MacTCP and then
  313.  *  copies it into the internal buffer: itsBuffer.  
  314.  *  You could probably set this up as an idle chore, but you will probably
  315.  *  want to force it once in awhile.
  316.  *
  317.  * Author: John Newlin
  318.  * Date: 15 June 1992
  319.  *
  320.  * Modified 18 June 1992
  321.  *   Changed the flow so that even if there is no data waiting to be read, a
  322.  *  read call will be issued, and if it times out, oh well.  This is because
  323.  *  of our relatively slow transfer times, and any other delays that may come
  324.  *  up.
  325.  *
  326.  **********************************/
  327.  
  328. #define kMaxBufferSpace   32768L      // Our buffer should never grow more than 32K
  329.  
  330.  
  331. void CTCPClient::ReadData (void)
  332. {
  333.    TCPStatusPB    theStatus;         // Connection Status
  334.    size_t         bufSpaceLeft;      // Amount of buffer space that is left.
  335.    size_t         bufSpaceNeeded;    // How big we need to make the buffer.
  336.    Size           theBufSize;
  337.    Size           amtOfDataToRead;   // amount of data to read in.
  338.    Ptr            tmpPtr;
  339.    Ptr            endPtr;
  340.    
  341.    TRY
  342.    {
  343.       if (this->itsBuffer == Null)
  344.       {
  345.          this->itsBuffer= NewHandle (1024);      // Good initial size.
  346.          tmpPtr= *(this->itsBuffer);
  347.          *tmpPtr= '\0';
  348.       }
  349.       
  350.          
  351.          // Check if there is data available.  If so read it in.
  352.       FailOSErr (itsStream->Status (&theStatus));
  353.       if (theStatus.amtUnreadData > 0)
  354.       {
  355.             // Lock down our buffer so we don't accidentally nuke ourselves.
  356.          MoveHHi (this->itsBuffer);
  357.          HLock (this->itsBuffer);
  358.  
  359.  
  360.             // figure out how much buffer space we have left.
  361.          tmpPtr= *(this->itsBuffer);
  362.          theBufSize= GetHandleSize (this->itsBuffer);
  363.          bufSpaceLeft= theBufSize - strlen (tmpPtr) - 1;
  364.          
  365.             // Make sure we have enough buffer space available
  366.          if (bufSpaceLeft < theStatus.amtUnreadData)
  367.          {
  368.                // Figure out how much space we need to allocate
  369.             bufSpaceNeeded= theStatus.amtUnreadData + strlen(tmpPtr) +1;
  370.  
  371.  
  372.             if (bufSpaceNeeded > kMaxBufferSpace) 
  373.                bufSpaceNeeded= kMaxBufferSpace;
  374.             
  375.             HUnlock (this->itsBuffer);
  376.             SetHandleSize (this->itsBuffer, bufSpaceNeeded);
  377.             FailMemError();
  378.          }
  379.          HUnlock (this->itsBuffer);
  380.       }
  381.       
  382.          // Now recalculate how much buffer space we have and read the data in
  383.       MoveHHi (this->itsBuffer);
  384.       HLock (this->itsBuffer);
  385.       tmpPtr= *(this->itsBuffer);
  386.       theBufSize= GetHandleSize (this->itsBuffer);
  387.       bufSpaceLeft= theBufSize - strlen (tmpPtr) - 1;
  388.  
  389.  
  390.             // Now read in the amount of data we can support.
  391.             // No bitching about brackets, if you can't figure it out, 
  392.             // you shouldn't be reading it!!
  393.       if (theStatus.amtUnreadData==0 || bufSpaceLeft<theStatus.amtUnreadData)
  394.          amtOfDataToRead= bufSpaceLeft;
  395.       else 
  396.          amtOfDataToRead= theStatus.amtUnreadData;
  397.   
  398.       endPtr= strrchr (tmpPtr, '\0');
  399.       FailOSErr (this->MyBufferReceiveData (endPtr, &amtOfDataToRead));
  400.       endPtr[amtOfDataToRead]= '\0';
  401.       
  402.       HUnlock (this->itsBuffer);
  403.    }
  404.    CATCH
  405.    {
  406.       HUnlock (this->itsBuffer);
  407.    }
  408.    ENDTRY;
  409.    
  410. }
  411.  
  412.  
  413.  
  414. /***********************************************
  415.  * ReleaseBuffer
  416.  *   This function realeases the buffer allocated by ReadData.
  417.  *   This is useful is you only want part of the data that was
  418.  *   read in by ReadData.
  419.  ***********************************************/
  420.  
  421. void CTCPClient::ReleaseBuffer (void)
  422. {
  423.     ForgetHandle (itsBuffer);
  424.     FailMemError();
  425. }
  426.  
  427.  
  428.  
  429. /*************************************************
  430.  * GetLine
  431.  *   This function takes a pointer to a buffer and copies one line of
  432.  *   data into it.  Includes the newline on the end.
  433.  *
  434.  *   Note: This DOES null terminate your line.
  435.  *************************************************/
  436.  
  437. void CTCPClient::GetLine (Ptr line)
  438. {
  439.     Ptr    tmpPtr= Null;
  440.     Ptr    endPtr= Null;
  441.     Size    howLong= 0;
  442.     
  443.     howLong= this->HowLongNextLine();
  444.     if (howLong > 0) 
  445.     {
  446.         TRY
  447.         {
  448.                 // Copy the data into the callers buffer.
  449.             MoveHHi (this->itsBuffer);
  450.             HLock (this->itsBuffer);
  451.             tmpPtr= *(this->itsBuffer);
  452.             strncpy (line, tmpPtr, howLong);
  453.             line[howLong]= '\0';
  454.             
  455.                 // Now we need to move the rest of the data
  456.             endPtr= (tmpPtr+howLong);
  457.             memmove (tmpPtr, endPtr, strlen (endPtr) + 1);
  458.             HUnlock (this->itsBuffer);
  459.         }
  460.         CATCH
  461.         {
  462.             HUnlock (this->itsBuffer);
  463.         }
  464.         ENDTRY;
  465.     }
  466.     return;
  467. }
  468.  
  469.  
  470.  
  471. /*********************************************
  472.  * HowLongNextLine
  473.  *   This function figures out how many characters are then next line.
  474.  *   The length includes the new line.  
  475.  *
  476.  *   The functionality here is in question.  If there is no newline should
  477.  *   I say how many characters are available up to the end of string, or should
  478.  *   I return Null.
  479.  *   If I agree to the first condition, then there must ALWAYS be a new line
  480.  *   if the sender wants the receiver (us) to get the data.  The reason this
  481.  *   is in question is because there may be data available from MacTCP that
  482.  *   we have no stuck into itsBuffer yet. 
  483.  *
  484.  *   Maybe if we hit the case with no newline, we should call ReadData,
  485.  *   and then try it again.  hmmmmmmm.....  What do you think???
  486.  *
  487.  *  Author: John Newlin
  488.  *  Date: 15 June 1992
  489.  **********************************************/
  490.         
  491. Size CTCPClient::HowLongNextLine (void)
  492. {
  493.     Ptr    tmpPtr;
  494.     Ptr    endPtr;
  495.     Size    length;
  496.     
  497.     if (this->itsBuffer == Null)
  498.     {
  499.         length= 0;
  500.     }
  501.     else
  502.     {
  503.             // Lock the buffer and put a pointer to the first character.
  504.         MoveHHi (this->itsBuffer);
  505.         HLock (this->itsBuffer);
  506.         tmpPtr= *(this->itsBuffer);
  507.  
  508.             // Find the end of line character.
  509.         endPtr= strchr (tmpPtr, '\n');
  510.         if (endPtr == Null)
  511.             length= strlen (tmpPtr);
  512.         else
  513.         {
  514.             char tmpChar= *endPtr;
  515.             *endPtr= '\0';
  516.             length= strlen (tmpPtr) + 1;
  517.             *endPtr= tmpChar;
  518.         }
  519.     }
  520.     
  521.     return length;
  522. }
  523.  
  524. /*=====================*/